package com.ww.exercise.coroutine.hard.q21

import kotlinx.coroutines.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import kotlin.system.measureTimeMillis

// 服务调用结果数据类
data class ServiceResult(
    val serviceName: String,
    val data: String,
    val success: Boolean = true,
    val error: String? = null
)

// 模拟服务A - 快速响应
suspend fun callServiceA(): ServiceResult {
    delay(1000) // 模拟1秒处理时间
    return ServiceResult("A", "Data from service A")
}

// 模拟服务B - 中等响应
suspend fun callServiceB(): ServiceResult {
    delay(2000) // 模拟2秒处理时间
    return ServiceResult("B", "Data from service B")
}

// 模拟服务C - 偶尔响应极慢
suspend fun callServiceC(): ServiceResult {
    // 50%概率响应缓慢(11秒)，超过5秒超时阈值
    val delayTime = if (Math.random() < 0.5) 3000L else 11000L
    delay(delayTime)
    return ServiceResult("C", "Data from service C")
}

// 修复后的协程方案实现
suspend fun coroutineBasedSolution(): List<ServiceResult> {
    val results = mutableListOf<ServiceResult>()

    // 使用SupervisorJob确保子协程失败不影响其他协程
    return withContext(Dispatchers.IO) {
        val supervisorJob = SupervisorJob(coroutineContext[Job])

        val deferredA = async(supervisorJob) { callServiceA() }
        val deferredB = async(supervisorJob) { callServiceB() }
        val deferredC = async(supervisorJob) { callServiceC() }

        try {
            // 全局超时设置为5秒
            withTimeout(5000) {
                // 等待所有服务完成
                results.add(deferredA.await())
                results.add(deferredB.await())
                results.add(deferredC.await())
            }
        } catch (e: TimeoutCancellationException) {
            // 超时后收集已完成的结果
            if (deferredA.isCompleted) {
                results.add(
                    try {
                        deferredA.await()
                    } catch (ce: CancellationException) {
                        ServiceResult("A", "", false, "cancelled due to timeout")
                    }
                )
            }
            if (deferredB.isCompleted) {
                results.add(
                    try {
                        deferredB.await()
                    } catch (ce: CancellationException) {
                        ServiceResult("B", "", false, "cancelled due to timeout")
                    }
                )
            }
            if (deferredC.isCompleted) {
                results.add(
                    try {
                        deferredC.await()
                    } catch (ce: CancellationException) {
                        ServiceResult("C", "", false, "cancelled due to timeout")
                    }
                )
            }

            println("协程方案: 超时! 收集部分结果")
        } catch (e: CancellationException) {
            // 捕获取消异常，避免传播
            println("协程方案: 操作被取消")
        } catch (e: Exception) {
            results.add(ServiceResult("System", "", false, e.message))
        } finally {
            // 安全取消，使用非阻塞方式
            supervisorJob.cancel()
            // 等待取消完成
            runCatching { supervisorJob.join() }
        }

        results
    }
}

// 线程池方案实现
fun threadPoolBasedSolution(): List<ServiceResult> {
    val results = mutableListOf<ServiceResult>()
    val executor = Executors.newFixedThreadPool(3)

    try {
        // 提交服务调用任务
        val futureA = executor.submit<ServiceResult> {
            Thread.sleep(1000) // 模拟1秒处理
            ServiceResult("A", "Data from service A")
        }

        val futureB = executor.submit<ServiceResult> {
            Thread.sleep(2000) // 模拟2秒处理
            ServiceResult("B", "Data from service B")
        }

        val futureC = executor.submit<ServiceResult> {
            val sleepTime = if (Math.random() < 0.5) 3000L else 11000L
            Thread.sleep(sleepTime) // 模拟可能超时的处理
            ServiceResult("C", "Data from service C")
        }

        val endTime = System.currentTimeMillis() + 5000 // 5秒超时

        // 尝试获取各服务结果，带剩余超时时间
        try {
            val remainingA = Math.max(0, endTime - System.currentTimeMillis())
            results.add(futureA.get(remainingA, TimeUnit.MILLISECONDS))
        } catch (e: TimeoutException) {
            futureA.cancel(true)
            results.add(ServiceResult("A", "", false, "timeout"))
        }

        try {
            val remainingB = Math.max(0, endTime - System.currentTimeMillis())
            results.add(futureB.get(remainingB, TimeUnit.MILLISECONDS))
        } catch (e: TimeoutException) {
            futureB.cancel(true)
            results.add(ServiceResult("B", "", false, "timeout"))
        }

        try {
            val remainingC = Math.max(0, endTime - System.currentTimeMillis())
            results.add(futureC.get(remainingC, TimeUnit.MILLISECONDS))
        } catch (e: TimeoutException) {
            // 尝试取消，但无法真正中断已经在运行的线程
            val cancelled = futureC.cancel(true)
            results.add(ServiceResult("C", "", false, "timeout"))
            println("线程池方案: C超时，取消尝试结果: $cancelled (可能仍在运行)")
        }

    } catch (e: Exception) {
        results.add(ServiceResult("System", "", false, e.message))
    } finally {
        // 关闭线程池释放资源
        executor.shutdown()
        if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
            executor.shutdownNow()
        }
    }

    return results
}

fun main() = runBlocking {
    // 测试协程方案
    println("=== 协程方案测试 ===")
    val coroutineTime = measureTimeMillis {
        val results = coroutineBasedSolution()
        println("返回结果: ${results.map { "${it.serviceName}=${if (it.success) "成功" else "失败(${it.error})"}" }}")
    }
    println("协程方案耗时: $coroutineTime ms\n")

    // 测试线程池方案
    println("=== 线程池方案测试 ===")
    val threadTime = measureTimeMillis {
        val results = threadPoolBasedSolution()
        println("返回结果: ${results.map { "${it.serviceName}=${if (it.success) "成功" else "失败(${it.error})"}" }}")
    }
    println("线程池方案耗时: $threadTime ms\n")
}
